package com.yf.notify.modules.notify.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.api.exception.ServiceException;
import com.yf.base.utils.BeanMapper;
import com.yf.job.service.JobService;
import com.yf.notify.enums.MsgState;
import com.yf.notify.enums.MsgType;
import com.yf.notify.jobs.MsgSendJob;
import com.yf.notify.modules.notify.dto.MsgDTO;
import com.yf.notify.modules.notify.dto.request.MsgQueryDTO;
import com.yf.notify.modules.notify.dto.request.MsgReceiverDTO;
import com.yf.notify.modules.notify.dto.request.MsgSendDTO;
import com.yf.notify.modules.notify.dto.request.MsgTestDTO;
import com.yf.notify.modules.notify.dto.response.MsgRespDTO;
import com.yf.notify.modules.notify.entity.Msg;
import com.yf.notify.modules.notify.entity.MsgRead;
import com.yf.notify.modules.notify.entity.MsgTmpl;
import com.yf.notify.modules.notify.mapper.MsgMapper;
import com.yf.notify.modules.notify.service.MsgPropService;
import com.yf.notify.modules.notify.service.MsgReadService;
import com.yf.notify.modules.notify.service.MsgService;
import com.yf.notify.modules.notify.service.MsgTmplService;
import com.yf.notify.modules.notify.utils.MsgUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 系统消息业务实现类
 * </p>
 *
 * @author 聪明笨狗
 * @since 2022-11-08 10:54
 */
@Service
public class MsgServiceImpl extends ServiceImpl<MsgMapper, Msg> implements MsgService {


    @Autowired
    private MsgTmplService msgTmplService;

    @Autowired
    private MsgReadService msgReadService;

    @Autowired
    private MsgPropService msgPropService;

    @Autowired
    private JobService jobService;

    @Override
    public IPage<MsgRespDTO> paging(PagingReqDTO<MsgDTO> reqDTO) {
        return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams());
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<String> ids) {
        this.removeByIds(ids);

        // 删除参数
        msgPropService.removeByMsg(ids);

        // 删除用户关联
        msgReadService.removeByMsg(ids);

    }

    @Override
    public IPage<MsgDTO> userPaging(PagingReqDTO<MsgQueryDTO> reqDTO) {
        return baseMapper.userPaging(reqDTO.toPage(), reqDTO.getParams());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public MsgDTO detailForRead(String msgId, String userId) {

        MsgDTO dto = this.detail(msgId);

        if(dto!=null && StringUtils.isNotBlank(dto.getId())){
            msgReadService.markRead(msgId, userId);
        }

        return dto;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(MsgSendDTO reqDTO) {

    }

    @Override
    public void sendNotify(MsgSendDTO reqDTO) {
        // 获得消息模板
        MsgTmpl tmpl = msgTmplService.getById(reqDTO.getTmplId());

        // 发信判断：1.模板开启了功能 && 2.指定方式为空或true && 3.收信账号不为空
        if(tmpl.getSmsOn()!=null
                && tmpl.getSmsOn()
                && !CollectionUtils.isEmpty(reqDTO.getTos())
                && (reqDTO.getUseSms()==null || reqDTO.getUseSms())){

            try{
                // 反应ID
                String id = this.prepareSms(tmpl, reqDTO.getTos(), reqDTO.getParams());
                // 交给任务去执行
                jobService.addCronJob(MsgSendJob.class,null, id);
            }catch (Exception e){
                log.error(e.getMessage());
            }
        }

        if(tmpl.getEmailOn()!=null
                && tmpl.getEmailOn()
                && !CollectionUtils.isEmpty(reqDTO.getTos())
                && (reqDTO.getUseEmail()==null || reqDTO.getUseEmail())){
            try {
                // 反应ID
                String id = this.prepareEmail(tmpl, reqDTO.getTos(), reqDTO.getParams());
                // 交给任务去执行
                jobService.addCronJob(MsgSendJob.class, null, id);
            }catch (Exception e){
                log.error(e.getMessage());
            }
        }

        if(tmpl.getImOn()!=null
                && tmpl.getImOn()
                && !CollectionUtils.isEmpty(reqDTO.getTos())
                && (reqDTO.getUseIm()==null || reqDTO.getUseIm())){
            // 保存数据即为发送
            this.prepareIm(tmpl, reqDTO.getTos(), reqDTO.getParams());
        }
    }

    @Override
    public void testNotify(MsgTestDTO reqDTO) {

        // 获得消息模板
        MsgTmpl tmpl = msgTmplService.getById(reqDTO.getTmplId());


        boolean effect = false;

        // 接收对象
        List<MsgReceiverDTO> tos = new ArrayList<>();
        MsgReceiverDTO to = new MsgReceiverDTO();
        BeanMapper.copy(reqDTO, to);
        tos.add(to);

        // 发信判断：1.模板开启了功能 && 2.指定方式为空或true && 3.收信账号不为空
        if(tmpl.getSmsOn()!=null
                && tmpl.getSmsOn()
                && StringUtils.isNotBlank(reqDTO.getMobile())){
            // 反应ID
            String id = this.prepareSms(tmpl, tos, reqDTO.getParams());
            // 交给任务去执行
            jobService.addCronJob(MsgSendJob.class,null, id);

            effect = true;
        }

        if(tmpl.getEmailOn()!=null
                && tmpl.getEmailOn()
                && StringUtils.isNotBlank(reqDTO.getEmail())){
            // 反应ID

            String id = this.prepareEmail(tmpl, tos, reqDTO.getParams());
            // 交给任务去执行
            jobService.addCronJob(MsgSendJob.class, null, id);

            effect = true;
        }

        if(tmpl.getImOn()!=null
                && tmpl.getImOn()
                && StringUtils.isNotBlank(reqDTO.getUserId())){
            // 保存数据即为发送
            this.prepareIm(tmpl, tos, reqDTO.getParams());

            effect = true;
        }

        if(!effect){
            throw new ServiceException("消息未发送，请确模板配置及接收者是否正确！");
        }
    }

    @Override
    public void triggerSend(List<String> ids) {

        // 重试次数
        for(String id: ids){
            // 交给任务去执行
            jobService.addCronJob(MsgSendJob.class, null, id);
        }
    }

    @Override
    public MsgDTO detail(String id) {
        Msg entity = this.getById(id);
        MsgDTO dto = new MsgDTO();
        BeanMapper.copy(entity, dto);
        return dto;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void smsNotify(String tmplId, List<MsgReceiverDTO> tos, Map<String, String> params) {

        // 获得消息模板
        MsgTmpl tmpl = msgTmplService.getById(tmplId);

        // 暂存数据
        String id = this.prepareSms(tmpl, tos, params);

        // 交给任务去执行
        jobService.addCronJob(MsgSendJob.class, null, id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void emailNotify(String tmplId, List<MsgReceiverDTO> tos, Map<String, String> params) {
        // 获得消息模板
        MsgTmpl tmpl = msgTmplService.getById(tmplId);
        // 暂存数据
        String id = this.prepareEmail(tmpl, tos, params);
        // 交给任务去执行
        jobService.addCronJob(MsgSendJob.class, null, id);
    }

    @Override
    public void imNotify(String tmplId, List<MsgReceiverDTO> tos, Map<String, String> params) {

        // 获得消息模板
        MsgTmpl tmpl = msgTmplService.getById(tmplId);
        // 暂存数据
        String id = this.prepareIm(tmpl, tos, params);
        // 交给任务去执行
        jobService.addCronJob(MsgSendJob.class, null, id);

    }


    /**
     * 准备站内信
     * @param tmpl
     * @param tos
     * @param params
     * @return
     */
    private String prepareIm(MsgTmpl tmpl, List<MsgReceiverDTO> tos, Map<String, String> params){

        if(CollectionUtils.isEmpty(tos)){
            throw new ServiceException("用户列表不能为空！");
        }

        if(tmpl==null){
            throw new ServiceException("消息模板不存在或短信模板未配置！");
        }

        // 消息内容
        String content = MsgUtils.parseMsg(tmpl.getTemplate(), params);

        // 保存本体
        Msg msg = new Msg();
        msg.setTitle(tmpl.getTitle());
        msg.setContent(content);
        msg.setTmplId(tmpl.getId());
        msg.setMsgType(MsgType.IM);
        msg.setSendState(MsgState.SENDED);

        MsgReceiverDTO to = tos.get(0);

        if(tos.size() > 1 || StringUtils.isBlank(to.getRealName())){
            msg.setReceiver(tos.size()+"个用户");
        }else{
            msg.setReceiver(to.getRealName());
        }


        this.save(msg);

        // 保存参数
        msgPropService.saveAll(msg.getId(), params);

        // 保存全部
        List<MsgRead> readList = new ArrayList<>();
        for(MsgReceiverDTO user: tos){
            MsgRead read = new MsgRead();
            read.setMsgId(msg.getId());
            read.setMsgType(msg.getMsgType());
            read.setReceiver(user.getRealName());
            read.setUserId(user.getUserId());
            read.setReadState(0);
            readList.add(read);
        }

        msgReadService.saveBatch(readList);
        return msg.getId();
    }
    /**
     * 保存短信类型消息，以便于发送
     * @param tmpl
     * @param tos
     * @param params
     */
    private String prepareSms(MsgTmpl tmpl, List<MsgReceiverDTO> tos, Map<String, String> params){


        if(CollectionUtils.isEmpty(tos)){
            throw new ServiceException("消息接收对象不能为空！");
        }

        if(tmpl==null || StringUtils.isBlank(tmpl.getSmsTmpl())){
            throw new ServiceException("消息模板不存在或短信模板未配置！");
        }

        if(tmpl.getSmsOn()==null || !tmpl.getSmsOn()){
            throw new ServiceException("此消息未开启，请编辑消息模板开启！");
        }

        List<String> mobiles = new ArrayList<>();
        for(MsgReceiverDTO item: tos){
            if(StringUtils.isNotBlank(item.getMobile())){
                mobiles.add(item.getMobile());
            }
        }

        if(CollectionUtils.isEmpty(mobiles)){
            throw new ServiceException("手机号码不能为空！");
        }

        // 消息内容
        String content = MsgUtils.parseMsg(tmpl.getTemplate(), params);

        // 保存本体
        Msg msg = new Msg();
        msg.setTitle(tmpl.getTitle());
        msg.setContent(content);
        msg.setTmplId(tmpl.getId());
        msg.setMsgType(MsgType.SMS);
        msg.setSendState(MsgState.PREPARE);
        if(mobiles.size() > 1){
            msg.setReceiver(mobiles.size()+"个手机");
        }else{
            msg.setReceiver(mobiles.get(0));
        }
        this.save(msg);

        // 保存参数
        msgPropService.saveAll(msg.getId(), params);

        // 保存全部
        List<MsgRead> readList = new ArrayList<>();
        for(MsgReceiverDTO item: tos){

            // 手机号为空
            if(StringUtils.isBlank(item.getMobile())){
                continue;
            }
            MsgRead read = new MsgRead();
            read.setMsgId(msg.getId());
            read.setMsgType(msg.getMsgType());
            read.setReceiver(item.getMobile());
            read.setUserId(item.getUserId());
            read.setReadState(0);
            readList.add(read);
        }
        msgReadService.saveBatch(readList);
        return msg.getId();
    }

    /**
     * 准备邮件类型以发送
     * @param tmpl
     * @param tos
     * @param params
     * @return
     */
    private String prepareEmail(MsgTmpl tmpl, List<MsgReceiverDTO> tos, Map<String, String> params){


        if(CollectionUtils.isEmpty(tos)){
            throw new ServiceException("消息接收对象不能为空！");
        }

        if(tmpl==null){
            throw new ServiceException("消息模板不存在或短信模板未配置！");
        }

        if(tmpl.getEmailOn()==null || !tmpl.getEmailOn()){
            throw new ServiceException("此消息未开启，请编辑消息模板开启！");
        }

        List<String> emails = new ArrayList<>();
        for(MsgReceiverDTO item: tos){
            if(StringUtils.isNotBlank(item.getEmail())){
                emails.add(item.getEmail());
            }
        }

        if(CollectionUtils.isEmpty(emails)){
            throw new ServiceException("邮箱不能为空！");
        }

        // 消息内容
        String body = MsgUtils.parseMsg(tmpl.getTemplate(), params);
        String subject = tmpl.getTitle();

        // 保存本体
        Msg msg = new Msg();
        msg.setTitle(subject);
        msg.setContent(body);
        msg.setTmplId(tmpl.getId());
        msg.setMsgType(MsgType.EMAIL);
        msg.setSendState(MsgState.PREPARE);
        if(emails.size() > 1){
            msg.setReceiver(emails.size()+"个邮箱");
        }else{
            msg.setReceiver(emails.get(0));
        }
        this.save(msg);

        // 保存参数
        msgPropService.saveAll(msg.getId(), params);

        // 保存全部
        List<MsgRead> readList = new ArrayList<>();
        for(MsgReceiverDTO item: tos){

            // 手机号为空
            if(StringUtils.isBlank(item.getEmail())){
                continue;
            }

            MsgRead read = new MsgRead();
            read.setMsgId(msg.getId());
            read.setMsgType(msg.getMsgType());
            read.setReceiver(item.getEmail());
            read.setUserId(item.getUserId());
            read.setReadState(0);
            readList.add(read);
        }

        msgReadService.saveBatch(readList);
        return msg.getId();
    }
}
